package com.zeny.coding.controller.admin.file;


import com.zeny.coding.dto.FileDto;
import com.zeny.coding.dto.Response;
import com.zeny.coding.enmus.FileUseEnum;
import com.zeny.coding.service.FileService;
import com.zeny.coding.util.Base64ToMultipartFile;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.xml.bind.ValidationException;
import java.io.*;

/**
 * <h2>文件上传</h2>
 *
 * @Author Zeny
 */
@SuppressWarnings("all")
@Slf4j
@RequestMapping("/file/admin")
@RestController
public class UploadController {
    @Value("${file.domain}")
    private String domain;

    @Value("${file.path}")
    private String path;

    @Autowired
    private FileService fileService;


    @PostMapping("/upload")
    public Response upload(@RequestBody FileDto fileDto) throws IOException, ValidationException {
        fileDto.valid();
        String use = fileDto.getUse();
        String suffix = fileDto.getSuffix();
        String shardBase64 = fileDto.getShard();
        MultipartFile shard = Base64ToMultipartFile.base64ToMultipart(shardBase64);
        //分片文件名 使用文件标识key
        String shardName = fileDto.getKey();
        //获取use从枚举中获取文件夹的名称
        FileUseEnum fileUseEnum = FileUseEnum.getByCode(use);
        //生成文件夹
        String folderName = fileUseEnum.name().toLowerCase();
        File folder = new File(path + folderName);
        if (!folder.exists()) {
            folder.mkdir();
        }
        //文件存储路径 相对路径
        String relativePath = new StringBuffer(folderName)
                .append(File.separator)
                .append(shardName)
                .append(".")
                .append(suffix)
                .toString();
        String localPath = relativePath + "." + fileDto.getShardIndex();
        //文件存储路径 绝对路径
        String absolutePath = path + localPath;
        File dest = new File(absolutePath);
        shard.transferTo(dest);
        //设置文件的相对路径
        fileDto.setPath(relativePath);
        //保存文件
        fileService.save(fileDto);
        //合并文件
        if (fileDto.getShardIndex().equals(fileDto.getShardTotal())) {
            this.merge(fileDto);
        }
        return new Response().success().data(fileDto);
    }

    private void merge(FileDto fileDto) {
        //分片总数
        Integer shardTotal = fileDto.getShardTotal();
        //文件的绝对路径
        String absolutePath = path + fileDto.getPath();
        File newFile = new File(absolutePath);
        InputStream in = null;
        OutputStream os = null;
        try {
            os = new FileOutputStream(newFile);
            for (int i = 1; i <= shardTotal; i++) {
                //本地保存分片地址
                String localPath = absolutePath + "." + i;
                File tempFile = new File(localPath);
                in = new FileInputStream(tempFile);
                int len = 0;
                byte[] buffer = new byte[1024 * 1024 * 20];//20MB
                while ((len = in.read(buffer)) != -1) {
                    os.write(buffer, 0, len);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        System.gc();
        new Thread(()->{
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //删除分片
            for (int i = 1; i <= shardTotal; i++) {
                //本地保存分片地址
                String localPath = absolutePath + "." + i;
                File tempFile = new File(localPath);
                System.out.println(tempFile.delete());
            }
        }).start();
    }
}
